#include "http_session.h"
#include "../log.h"
#include "http_parser.h"
#include <cstdint>
#include <memory>
#include <sstream>

namespace MYHTTP
{

HttpSession::HttpSession(Socket::ptr sock, bool owner)
:SocketStream(sock, owner){}

//接收HTTP请求
HttpRequest::ptr HttpSession::recvRequest()
{
    HttpRequestParser::ptr parser = std::make_shared<HttpRequestParser>();
    //获取HttpRequest协议解析的缓存大小
    uint64_t buffer_size = HttpRequestParser::GetHttpRequestBufferSize();
    std::shared_ptr<char> buffer(new char[buffer_size], [](char* ptr){
        delete [] ptr;
    });

    char* data = buffer.get();
    int offset = 0;
    do 
    {
        int len = read(data + offset, buffer_size - offset);
        if(len <= 0)
        {
            return nullptr;
        }    
        len += offset;
        //解析协议，已经解析的数据被删除 返回实际解析的长度
        size_t nparse = parser->execute(data, len);
        if(parser->hasError())
        {
            close();
            log_error("execute has error");
            return nullptr;
        }
        offset = len - nparse; //data中剩余没有解析的字符数
        if(parser->isFinished())
        {
            break;
        }
    }while (true);

    //获取 消息体的长度
    int64_t length = parser->getContentLength();
    if(length > 0)
    {
        std::string body;
        body.resize(length);

        int len = 0;
        if(length >= offset)
        {
            memcpy(&body[0], data, offset);
            len = offset;
        }
        else 
        {
            memcpy(&body[0], data, length);
            len = length;
        }

        length -= offset; 
        //如果还有消息体的内容没有读完
        if(length > 0)
        {
            //继续接受后面的数据
            if(readFixSize(&body[len], length) <= 0)
            {
                close();
                log_error("readFixeSize error");
                return nullptr;
            }
        }
        parser->getData()->setBody(body);
    }
    parser->getData()->init();
    return parser->getData();
}

//发送HTTP响应
int HttpSession::sendResponse(HttpResponse::ptr rsp)
{
    std::stringstream ss;
    ss << *rsp;
    std::string data = ss.str();
    return writeFixSize(data.c_str(), data.size());
}

} //MYHTTP













